import {Injectable} from '@angular/core';
import {Hero} from '../hero';
// import { HEROS } from '../mock-heros'
import {Observable, of} from 'rxjs';
import {MessageService} from './message.service';
import {HttpClient, HttpHeaders} from '@angular/common/http';
import {catchError, map, tap} from 'rxjs/operators';
import {HeroDetailComponent} from '../hero-detail/hero-detail.component';

@Injectable({
  providedIn: 'root'
})
export class HeroService {

  private heroUrl: string = 'api/heros';

  constructor(
    private messageService: MessageService,
    private http: HttpClient,
  ) {
  }

  getHeros(): Observable<Hero[]> {

    return this.http.get<Hero[]>(this.heroUrl).pipe(
      tap(heros => this.log(`fetched $heros`)),
      catchError(this.handleError('getHeros', []))
    );
  }

  /**
   * Handle Http operation that failed.
   * Let the app continue.
   * @param operation - name of the operation that failed
   * @param result - optional value to return as the observable result
   */
  private handleError<T>(operation: string = 'operation', result?: T) {
    return (error: any): Observable<T> => {

      // TODO: send the error to remote logging infrastructure
      console.log(error); // log to console instead

      // TODO: better job of transforming error for user consumption
      this.log(`${operation} failed: ${error.message}`);

      // Let the app keep running by returning an empty result.
      return of(result as T);
    };
  }


  private log(message: string): void {
    this.messageService.add('HeroService ' + message);
  }

  getHero(id: number): Observable<Hero> {
    const url = `${this.heroUrl}/${id}`;
    return this.http.get<Hero>(url).pipe(
      tap(_ => this.log(`fetched hero id=${id}`)),
      catchError(this.handleError<Hero>(`getHero id=${id}`))
    );
  }


  updateHero(hero: Hero): Observable<any> {
    const httpOptions = {headers: new HttpHeaders({'Content-type': 'application/json'})};
    return this.http.put(this.heroUrl, hero, httpOptions).pipe(
      tap(_ => this.log(`update hero ${hero.id} ${hero.name}`)),
      catchError(this.handleError<any>('update'))
    );
  }


  addHero(hero: Hero): Observable<Hero> {

    return this.http.post<Hero>(this.heroUrl, hero, {headers: new HttpHeaders({'Content-type': 'application/json'})}).pipe(
      catchError(this.handleError<Hero>('add'))
    );
  }


  delete(hero: Hero | number): Observable<Hero> {
    const id = typeof hero === 'number' ? hero : hero.id;
    const url = `${this.heroUrl}/${id}`;

    const httpOptions = {headers: new HttpHeaders({'Content-type': 'application/json'})};
    return this.http.delete<Hero>(url, httpOptions).pipe(
      tap(_ => this.log(`delete`)),
      catchError(this.handleError<Hero>('delete hero'))
    );
  }


  searchHeros(term: string): Observable<Hero[]> {
    if (!term.trim()) {
      return of([]);
    }

    return this.http.get<Hero[]>(`api/heros/?name=${term}`).pipe(
      tap(_ => this.log('search')),
      catchError(this.handleError<Hero[]>('searchHeros', []))
    );

  }


}
